﻿/**
 * @file units.h
 * @brief 单位转换系统的核心头文件
 * @author [WJ]
 * @date [2025/08/08]
 */
#pragma once

#include <functional>
#include <memory>
#include <string>

/**
 * @namespace Units
 * @brief 包含单位转换系统的所有组件
 */
namespace Units {
/**
 * @enum ErrorCode
 * @brief 定义单位转换系统中可能出现的错误类型
 */
enum class ErrorCode {
  Success = 0,             ///< 操作成功
  InvalidHandle,           ///< 无效的句柄
  InvalidParameter,        ///< 无效的参数
  DimensionNotFound,       ///< 找不到指定的量纲
  UnitNotFound,            ///< 找不到指定的单位
  ConversionFailed,        ///< 转换失败
  CustomConversionExists,  ///< 自定义转换已存在
  FileIOError,             ///< 文件I/O错误
  ConfigParseError,        ///< 配置解析错误
  InvalidUnit,             ///< 无效的单位
  DefinedUnitsParseError,  ///< 已定义单位解析错误
  UnknownError             ///< 未知错误
};

/**
 * @brief 将错误码转换为可读的错误字符串
 * @param code 错误码
 * @return 错误字符串的常量指针
 */
const char *errorString(ErrorCode code);

/**
 * @brief 日志回调函数类型
 * @param type 日志类型（如"ERROR"、"INFO"等）
 * @param message 日志消息内容
 */
using LogCallback = std::function<void(const std::string & /*type,eg.ERROR*/,
                                       const std::string &)>;

/**
 * @brief 单位变更回调函数类型
 * @param owner 回调所有者的指针
 * @param dimension 发生变化的量纲
 * @param newUnit 新的单位
 */
typedef std::function<void(void *, const std::string &, const std::string &)>
    UnitChangedCallback;

/**
 * @brief 单位变更回调自动删除器类型
 * @note 当此智能指针被销毁时，会自动移除对应的观察者
 */
typedef std::shared_ptr<std::function<void()>> UnitChangedCallbackAutoDeleter;

/**
 * @class UnitSystem
 * @brief 单位转换系统的主类，提供单位转换、配置管理等功能
 * @note 此类采用单例模式设计
 */
class UnitSystem {
  UnitSystem(const UnitSystem &) = delete;
  UnitSystem &operator=(const UnitSystem &) = delete;

 public:
  /**
   * @brief 构造函数
   */
  UnitSystem();

  /**
   * @brief 获取单例实例
   * @return UnitSystem的引用
   */
  static UnitSystem &instance();

  /**
   * @brief 设置指定量纲的基准单位
   * @param dimension 量纲名称
   * @param unit 单位名称
   * @return 操作结果码
   */
  ErrorCode setBaseUnit(const std::string &dimension, const std::string &unit);

  /**
   * @brief 设置指定量纲的当前单位
   * @param dimension 量纲名称
   * @param unit 单位名称
   * @return 操作结果码
   */
  ErrorCode setCurrentUnit(const std::string &dimension,
                           const std::string &unit);

  /**
   * @brief 获取指定量纲的基准单位
   * @param dimension 量纲名称
   * @param result 用于存储结果的字符串引用
   * @return 操作结果码
   */
  ErrorCode getBaseUnit(const std::string &dimension,
                        std::string &result) const;

  /**
   * @brief 获取指定量纲的当前单位
   * @param dimension 量纲名称
   * @param result 用于存储结果的字符串引用
   * @return 操作结果码
   */
  ErrorCode getCurrentUnit(const std::string &dimension,
                           std::string &result) const;

  /**
   * @brief 转换带单位的测量值到目标单位
   * @param measurement 带单位的测量值字符串
   * @param to 目标单位
   * @param result 用于存储转换结果的引用
   * @return 操作结果码
   */
  ErrorCode convert(const std::string &measurement, const std::string &to,
                    double &result);

  /**
   * @brief 转换值从一个单位到另一个单位
   * @param value 要转换的值
   * @param from 源单位
   * @param to 目标单位
   * @param result 用于存储转换结果的引用
   * @return 操作结果码
   */
  ErrorCode convert(double value, const std::string &from,
                    const std::string &to, double &result);

  /**
   * @brief 将值转换为指定量纲的基准单位
   * @param value 要转换的值
   * @param dimension 量纲名称
   * @param result 用于存储转换结果的引用
   * @return 操作结果码
   */
  ErrorCode convertToBase(double value, const std::string &dimension,
                          double &result);

  /**
   * @brief 从指定量纲的基准单位转换值
   * @param value 要转换的值
   * @param dimension 量纲名称
   * @param result 用于存储转换结果的引用
   * @return 操作结果码
   */
  ErrorCode convertFromBase(double value, const std::string &dimension,
                            double &result);

  /**
   * @brief 注册自定义单位转换关系
   * @param name 自定义单位名称
   * @param measurement 自定义单位的定义（带单位的测量值）
   * @return 操作结果码
   */
  ErrorCode registerUserDefinedUnit(const std::string &name,
                                    const std::string &measurement);

  /**
   * @brief 注册当前单位变更观察者
   * @param owner 观察者的所有者指针
   * @param observer 观察者回调函数
   * @return 自动删除器，当删除器被销毁时自动移除观察者
   */
  UnitChangedCallbackAutoDeleter registerCurrentUnitChangedObserver(
      void *owner, UnitChangedCallback observer);

  /**
   * @brief 通知所有观察者单位变更
   * @param dimension 发生变更的量纲
   * @param newUnit 新的单位
   */
  void notifyCurrentUnitChanged(const std::string &dimension,
                                const std::string &newUnit);

  /**
   * @brief 注册日志回调函数
   * @param logger 日志回调函数
   */
  void registerLogger(LogCallback logger);

  /**
   * @brief 从配置文件加载单位系统配置
   * @param configFile 配置文件路径
   * @return 操作结果码
   */
  ErrorCode loadFromConfigFile(const std::string &configFile);

  /**
   * @brief 将单位系统配置保存到文件
   * @param outputFile 输出文件路径
   * @return 操作结果码
   */
  ErrorCode saveToConfigFile(const std::string &outputFile);

  /**
   * @brief 从文件加载已定义的单位
   * @param filename 包含已定义单位的文件路径
   * @return 操作结果码
   */
  ErrorCode loadDefinedUnitsFromFile(const std::string &filename);

 private:
  /**
   * @class UnitSystem::Private
   * @brief 实现细节类，遵循PIMPL模式
   */
  class Private;
  std::unique_ptr<Private> d;  ///< 指向私有实现的指针
};

/**
 * @brief 测试单位系统功能
 */
void testUnitSystem();

/**
 * @brief 测试单位系统的序列化功能
 */
void testUnitSystemSerialization();
}  // namespace Units